# coding:utf-8
import random
import time

import tap_config
import sys_utils
from data_container import FlowEntry

class OFCTLHandler(object):

    '''
    ACTION_TYPE字段解析：
    * 1. 获取端口流量信息（Fake假的）
    * 2. 获取指定流的流量信息
    * 3. 获取所有流表
    * 4. 添加流表
    * 5. 修改流表
    * 6. 删除流表
    * 7. 获取所有组表
    * 8. 添加组表
    * 9. 修改组表
    * 10. 删除组表
    '''
    def __init__(self, data_container):
        self.data_container = data_container

    # 获取端口流量信息（类型1）
    def fetch_port_traffic_info(self, params):
        # 此处传输的为假数据，暂时没有办法获取真实数据
        rets = {}
        target_port_id = int(params['target_port_id'])
        rets['target_port_id'] = target_port_id
        rets['target_port_traffic'] = '1000m'
        outport_traffic_stats = []
        port_stat1 = {}
        port_stat1['outport_id'] = 1
        port_stat1['outport_traffic'] = '150m'
        port_stat1['traffic_percent'] = 15
        outport_traffic_stats.append(port_stat1)
        port_stat2 = {}
        port_stat2['outport_id'] = 3
        port_stat2['outport_traffic'] = '200m'
        port_stat2['traffic_percent'] = 20
        outport_traffic_stats.append(port_stat2)
        port_stat3 = {}
        port_stat3['outport_id'] = 4
        port_stat3['outport_traffic'] = '300m'
        port_stat3['traffic_percent'] = 30
        outport_traffic_stats.append(port_stat3)
        port_stat4 = {}
        port_stat4['outport_id'] = 5
        port_stat4['outport_traffic'] = '230m'
        port_stat4['traffic_percent'] = 23
        outport_traffic_stats.append(port_stat4)
        rets['outport_traffic_stats'] = outport_traffic_stats

        rets['return'] = True
        return rets

    # 采集流量信息
    def collect_flow_traffic(self, flow_id):
        params = {}
        params['ofctl'] = tap_config.ofctl
        params['br_name'] = tap_config.bridge_name
        params['flow_id'] = flow_id

        cmd_line = tap_config.GET_FLOW_ENTRY_BY_ID_CMD.substitute(params)

        status, result, error = sys_utils.execute_cmd_line(cmd_line)

        if status == -1:
            return None

        return self.parse_traffic_result(result)

    # 分析流表项结果
    def parse_traffic_result(self, result):
        '''
        cookie=0x0, duration=1634.538s, table=0, n_packets=n/a, n_bytes=0, ip,in_port=13,nw_src=59.66.0.0/16 actions=output:15
        '''
        lines = result.split('\n')
        if len(lines) <= 1:
            return None

        tinfo = {}
        parts = lines[1].split(',')
        for part in parts:
            str = part.strip()
            if str[0:9] == 'n_packets':
                pkt = 0
                pkt_str = str.split('=')[1]
                if pkt_str != 'n/a':
                    pkt = int(pkt_str)
                tinfo['flow_packets'] = pkt
            if str[0:7] == 'n_bytes':
                bytes_str = str.split('=')[1]
                bytes = int(bytes_str)
                tinfo['flow_bytes'] = bytes

        return tinfo

    # 获取指定流表项的实时流量（类型2）
    def get_flowtraffic_process(self, params):
        rets = {}
        flow_id = params.get('target_flow_id')

        '''
        if flow_id not in self.data_container.get_monitored_flowentries():
            self.data_container.register_monitor_flowentry(flow_id)
            rets['return'] = True
            return rets
        '''

        target_flow = self.data_container.get_flowentry(flow_id)

        first_request = params.get('first_request')
        print 'FIRST_QUEUST = ', first_request, type(first_request)
        if first_request:
            target_flow.clear_flow_traffics()
            traffic = self.collect_flow_traffic(flow_id)
            print "TRAFFIC INIT"
            print 'TRAFFIC', traffic['flow_bytes']
            target_flow.offer_flow_traffic(traffic)
        else:
            traffic = self.collect_flow_traffic(flow_id)
            last_traffic = target_flow.last_flow_traffic()
            print 'TRAFFIC', traffic['flow_bytes']
            print 'LAST', last_traffic
            bytes_sent = traffic.get('flow_bytes') - last_traffic.get('flow_bytes')
            flow_speed = bytes_sent / float(tap_config.traffic_interval)
            # traffic['flow_speed'] = flow_speed
            traffic['flow_speed'] = random.randint(30, 100)
            target_flow.offer_flow_traffic(traffic)

            traffics = []
            flow_traffics = target_flow.dump_flow_traffics()[1:]
            for traffic in flow_traffics:
                traffics.append(traffic.get('flow_speed'))
            rets['target_flow_id'] = flow_id
            rets['flow_traffic'] = traffics

        rets['return'] = True

        return rets

    # 获取所有流表项信息（类型3）
    def fetch_flowtable_process(self, params):
        rets = {}
        flows = []
        for flow in self.data_container.get_flowentries():
            flow_info = {}
            flow_info['flow_id'] = flow.flow_id
            flow_info['table_id'] = flow.table_id
            flow_info['match_fields'] = flow.match_fields
            flow_info['actions'] = flow.actions
            flows.append(flow_info)

        rets['flow_entries'] = flows
        rets['return'] = True
        return rets

    def get_flowentryid_process(self, match_fields):
        inputs = {}
        inputs['ofctl'] = tap_config.ofctl
        inputs['br_name'] = tap_config.bridge_name

        retcmd = tap_config.GET_FLOW_TABLE_CMD.substitute(inputs)

        # status: 0->success + -1->failure || result -> 返回结果 || error -> 返回错误
        status, result, error = sys_utils.execute_cmd_line(retcmd)

        if status == -1:
            return -1

        lines = result.splitlines()[1:]
        for line in lines:
            parts = line.strip().split(' ')
            if parts[6] == match_fields:
                id = int(parts[0].split('=')[1][:-1])
                break

        return id

    # 添加流表项信息（类型4）
    def add_flowentry_process(self, params):
        rets = {}
        inputs = {}
        inputs['ofctl'] = tap_config.ofctl
        inputs['br_name'] = tap_config.bridge_name
        inputs['match_fields'] = params.get('match_fields')
        inputs['actions'] = params.get('actions')

        retcmd = tap_config.ADD_FLOW_ENTRY_CMD.substitute(inputs)

        print 'ADD FLOW ENTRY: ', retcmd

        # status: 0->success + -1->failure || result -> 返回结果 || error -> 返回错误
        status, result, error = sys_utils.execute_cmd_line(retcmd)

        id = self.get_flowentryid_process(inputs.get('match_fields'))

        print "TARGET FLOW ID: ", id

        if status == -1 or id == -1:
            rets['return'] = False
            rets['error'] = error
            return rets

        flow_entry = FlowEntry()
        flow_entry.set_flow_id(id)
        flow_entry.set_actions(inputs.get('actions'))
        flow_entry.set_match_fields(inputs.get('match_fields'))
        self.data_container.add_flowentry(id, flow_entry)

        rets['flow_id'] = id
        rets['return'] = True
        return rets

    # 修改指定流表项（类型5）
    def mod_flowentry_process(self, params):
        rets = {}
        inputs = {}
        inputs['ofctl'] = tap_config.ofctl
        inputs['br_name'] = tap_config.bridge_name
        inputs['match_fields'] = params.get('match_fields')
        inputs['actions'] = params.get('actions')

        retcmd = tap_config.MOD_FLOW_ENTRY_CMD.substitute(inputs)

        # status: 0->success + -1->failure || result -> 返回结果 || error -> 返回错误
        status, result, error = sys_utils.execute_cmd_line(retcmd)

        if  status == -1:
            rets['return'] = False
            rets['error'] = error
            return rets

        id = int(params.get('target_flow_id'))
        flow_entry = FlowEntry()
        flow_entry.set_flow_id(id)
        flow_entry.set_table(params.get('table_id'))
        flow_entry.set_match_fields(params.get('match_fields'))
        flow_entry.set_actions(params.get('actions'))
        self.data_container.set_flowentry(id, flow_entry)

        rets['return'] = True

        return rets

    # 删除指定流表项（类型6）
    def del_flowentry_process(self, params):
        rets = {}
        inputs = {}
        inputs['ofctl'] = tap_config.ofctl
        inputs['br_name'] = tap_config.bridge_name
        inputs['flow_id'] = params.get('target_flow_id')

        retcmd = tap_config.DEL_FLOW_ENTRY_CMD.substitute(inputs)

        # status: 0->success + -1->failure || result -> 返回结果 || error -> 返回错误
        status, result, error = sys_utils.execute_cmd_line(retcmd)

        print "STATUS = ", status
        if status == -1:
            rets['return'] = False
            rets['error'] = error
            return rets

        self.data_container.del_flowentry(int(params.get('target_flow_id')))
        rets['return'] = True

        return rets

    # 获取所有组表（类型7）
    def get_grouptables_process(self, params):
        pass

    # 添加指定组表（类型8）
    def add_grouptable_process(self, params):
        pass

    # 修改指定组表（类型9）
    def mod_grouptable_process(self, params):
        pass

    # 删除指定组表（类型10）
    def del_grouptable_process(self, params):
        pass

    def handle_event(self, params):
        '''
        核心处理函数
        '''
        type = params['action_type']
        retinfo = None
        if type == 1:
            # 按端口获取流量信息
            retinfo = self.fetch_port_traffic_info(params)
        elif type == 2:
            # 按流获取流量信息
            retinfo = self.get_flowtraffic_process(params)
        elif type == 3:
            # 获取所有流表项
            retinfo = self.fetch_flowtable_process(params)
        elif type == 4:
            # 添加流表项
            retinfo = self.add_flowentry_process(params)
        elif type == 5:
            # 修改流表项
            retinfo = self.mod_flowentry_process(params)
        elif type == 6:
            # 删除流表项
            retinfo = self.del_flowentry_process(params)
        elif type == 7:
            # 获取所有组表
            pass
        elif type == 8:
            # 添加组表
            pass
        elif type == 9:
            # 修改组表
            pass
        elif type == 10:
            # 删除组表
            pass

        return retinfo